#ifndef _THREAD_POOL_H
#define _THREAD_POOL_H

#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>

class ThreadPool
{
public:
    static ThreadPool& getInstance(int numThreads = 4);

    template <typename Func, typename... Args>
    void enqueue(Func&& func, Args&&... args)
    {
        auto task = std::make_shared<std::function<void()>>(
            std::bind(std::forward<Func>(func), std::forward<Args>(args)...));

        addTask([task]() { (*task)(); });
    }

private:
    ThreadPool(int numThreads);
    ~ThreadPool();
    void worker();
    void addTask(std::function<void()> func);

    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queueMutex;
    std::condition_variable condition;
    std::atomic<bool> stop;

    // Delete copy constructor and assignment operator to enforce singleton property
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;
};

#endif // _THREAD_POOL_H
